package com.eudon.genius.api.core.parser.component;

import com.eudon.genius.api.core.dto.ApiInfo;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.comments.JavadocComment;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.javadoc.Javadoc;
import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration;
import com.github.javaparser.resolution.types.ResolvedReferenceType;
import com.github.javaparser.resolution.types.ResolvedType;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 类型解析器
 * 负责递归解析自定义类型，提取字段信息，避免循环引用
 *
 * @author eudon
 * @since 2025/9/25
 */
@Slf4j
public class TypeResolver {

    /**
     * 基本类型集合
     */
    private static final Set<String> PRIMITIVE_TYPES;

    static {
        Set<String> types = new HashSet<>();
        types.add("byte");
        types.add("short");
        types.add("int");
        types.add("long");
        types.add("float");
        types.add("double");
        types.add("boolean");
        types.add("char");
        types.add("Byte");
        types.add("Short");
        types.add("Integer");
        types.add("Long");
        types.add("Float");
        types.add("Double");
        types.add("Boolean");
        types.add("Character");
        types.add("String");
        types.add("BigDecimal");
        types.add("BigInteger");
        types.add("Date");
        types.add("LocalDate");
        types.add("LocalDateTime");
        types.add("LocalTime");
        PRIMITIVE_TYPES = Collections.unmodifiableSet(types);
    }

    /**
     * 集合类型集合
     */
    private static final Set<String> COLLECTION_TYPES;

    static {
        Set<String> types = new HashSet<>();
        types.add("List");
        types.add("java.util.List");
        types.add("ArrayList");
        types.add("java.util.ArrayList");
        types.add("LinkedList");
        types.add("java.util.LinkedList");
        types.add("Set");
        types.add("java.util.Set");
        types.add("HashSet");
        types.add("java.util.HashSet");
        types.add("LinkedHashSet");
        types.add("java.util.LinkedHashSet");
        types.add("TreeSet");
        types.add("java.util.TreeSet");
        types.add("Collection");
        types.add("java.util.Collection");
        COLLECTION_TYPES = Collections.unmodifiableSet(types);
    }

    /**
     * Map类型集合
     */
    private static final Set<String> MAP_TYPES;

    static {
        Set<String> types = new HashSet<>();
        types.add("Map");
        types.add("java.util.Map");
        types.add("HashMap");
        types.add("java.util.HashMap");
        types.add("LinkedHashMap");
        types.add("java.util.LinkedHashMap");
        types.add("TreeMap");
        types.add("java.util.TreeMap");
        types.add("ConcurrentHashMap");
        types.add("java.util.concurrent.ConcurrentHashMap");
        MAP_TYPES = Collections.unmodifiableSet(types);
    }

    /**
     * 类型解析缓存，避免重复解析和循环引用
     */
    private final Map<String, List<ApiInfo.Parameter>> typeCache = new ConcurrentHashMap<>();

    /**
     * 正在解析的类型集合，用于检测循环引用
     */
    private final ThreadLocal<Set<String>> resolvingTypes = ThreadLocal.withInitial(HashSet::new);

    /**
     * 判断是否为基本类型
     *
     * @param typeName 类型名称
     * @return 是否为基本类型
     */
    public boolean isPrimitiveType(String typeName) {
        if (typeName == null || typeName.isEmpty()) {
            return false;
        }

        // 移除泛型信息
        String baseType = typeName;
        if (baseType.contains("<")) {
            baseType = baseType.substring(0, baseType.indexOf("<"));
        }

        return PRIMITIVE_TYPES.contains(baseType);
    }

    /**
     * 判断是否为集合类型
     *
     * @param typeName 类型名称
     * @return 是否为集合类型
     */
    public boolean isCollectionType(String typeName) {
        if (typeName == null || typeName.isEmpty()) {
            return false;
        }

        String baseType = typeName;
        if (baseType.contains("<")) {
            baseType = baseType.substring(0, baseType.indexOf("<"));
        }

        return COLLECTION_TYPES.contains(baseType) || baseType.endsWith("[]");
    }

    /**
     * 判断是否为Map类型
     *
     * @param typeName 类型名称
     * @return 是否为Map类型
     */
    public boolean isMapType(String typeName) {
        if (typeName == null || typeName.isEmpty()) {
            return false;
        }

        String baseType = typeName;
        if (baseType.contains("<")) {
            baseType = baseType.substring(0, baseType.indexOf("<"));
        }

        return MAP_TYPES.contains(baseType);
    }

    /**
     * 解析类型的字段信息
     *
     * @param type 类型
     * @return 字段信息列表
     */
    public List<ApiInfo.Parameter> resolveTypeFields(Type type) {
        try {
            ResolvedType resolvedType = type.resolve();
            return resolveTypeFields(resolvedType);
        } catch (Exception e) {
            log.warn("无法解析类型: {}, 错误: {}", type.asString(), e.getMessage());
            return new ArrayList<>();
        }
    }

    /**
     * 解析已解析类型的字段信息
     *
     * @param resolvedType 已解析的类型
     * @return 字段信息列表
     */
    public List<ApiInfo.Parameter> resolveTypeFields(ResolvedType resolvedType) {
        String typeName = resolvedType.describe();

        // 检查缓存
        if (typeCache.containsKey(typeName)) {
            return new ArrayList<>(typeCache.get(typeName));
        }

        // 检查循环引用
        Set<String> currentResolvingTypes = resolvingTypes.get();
        if (currentResolvingTypes.contains(typeName)) {
            log.debug("检测到循环引用，跳过类型: {}", typeName);
            return new ArrayList<>();
        }

        try {
            currentResolvingTypes.add(typeName);

            List<ApiInfo.Parameter> fields = new ArrayList<>();

            // 处理基本类型
            if (isPrimitiveType(typeName)) {
                return fields;
            }

            // 处理集合类型
            if (isCollectionType(typeName)) {
                fields.addAll(resolveCollectionType(resolvedType));
            }
            // 处理Map类型
            else if (isMapType(typeName)) {
                fields.addAll(resolveMapType(resolvedType));
            }
            // 处理自定义类型
            else if (resolvedType.isReferenceType()) {
                fields.addAll(resolveCustomType(resolvedType.asReferenceType()));
            }

            // 缓存结果
            typeCache.put(typeName, new ArrayList<>(fields));

            return fields;

        } finally {
            currentResolvingTypes.remove(typeName);
        }
    }

    /**
     * 解析集合类型
     */
    private List<ApiInfo.Parameter> resolveCollectionType(ResolvedType resolvedType) {
        List<ApiInfo.Parameter> fields = new ArrayList<>();

        if (resolvedType.isReferenceType()) {
            ResolvedReferenceType refType = resolvedType.asReferenceType();

            // 获取泛型参数
            if (!refType.getTypeParametersMap().isEmpty()) {
                List<ResolvedType> typeParameters = refType.typeParametersValues();
                if (!typeParameters.isEmpty()) {
                    ResolvedType elementType = typeParameters.get(0);

                    // 创建集合元素字段
                    ApiInfo.Parameter elementField = new ApiInfo.Parameter();
                    elementField.setParameterName("items");
                    elementField.setParameterDesc("集合元素");
                    elementField.setParameterType(elementType.describe());
                    elementField.setSimpleTypeName(getSimpleTypeName(elementType.describe()));
                    elementField.setIsPrimitive(isPrimitiveType(elementType.describe()));
                    elementField.setNullable(true);

                    // 如果元素不是基本类型，递归解析
                    if (!Boolean.TRUE.equals(elementField.getIsPrimitive())) {
                        elementField.setFields(resolveTypeFields(elementType));
                    }

                    fields.add(elementField);
                }
            }
        }

        return fields;
    }

    /**
     * 解析Map类型
     */
    private List<ApiInfo.Parameter> resolveMapType(ResolvedType resolvedType) {
        List<ApiInfo.Parameter> fields = new ArrayList<>();

        if (resolvedType.isReferenceType()) {
            ResolvedReferenceType refType = resolvedType.asReferenceType();

            // 获取泛型参数
            if (!refType.getTypeParametersMap().isEmpty()) {
                List<ResolvedType> typeParameters = refType.typeParametersValues();
                if (typeParameters.size() >= 2) {
                    ResolvedType valueType = typeParameters.get(1);

                    // 创建Map值字段
                    ApiInfo.Parameter valueField = new ApiInfo.Parameter();
                    valueField.setParameterName("additionalProperties");
                    valueField.setParameterDesc("Map值");
                    valueField.setParameterType(valueType.describe());
                    valueField.setSimpleTypeName(getSimpleTypeName(valueType.describe()));
                    valueField.setIsPrimitive(isPrimitiveType(valueType.describe()));
                    valueField.setNullable(true);

                    // 如果值不是基本类型，递归解析
                    if (!Boolean.TRUE.equals(valueField.getIsPrimitive())) {
                        valueField.setFields(resolveTypeFields(valueType));
                    }

                    fields.add(valueField);
                }
            }
        }

        return fields;
    }

    /**
     * 解析自定义类型
     */
    private List<ApiInfo.Parameter> resolveCustomType(ResolvedReferenceType resolvedType) {
        List<ApiInfo.Parameter> fields = new ArrayList<>();

        try {
            ResolvedReferenceTypeDeclaration typeDeclaration = resolvedType.getTypeDeclaration().orElse(null);
            if (typeDeclaration == null) {
                return fields;
            }

            // 获取类声明
            if (typeDeclaration.toAst().isPresent() &&
                    typeDeclaration.toAst().get() instanceof ClassOrInterfaceDeclaration) {

                ClassOrInterfaceDeclaration classDecl = (ClassOrInterfaceDeclaration) typeDeclaration.toAst().get();
                fields.addAll(parseClassFields(classDecl));
            }

        } catch (Exception e) {
            log.warn("解析自定义类型失败: {}, 错误: {}", resolvedType.describe(), e.getMessage());
        }

        return fields;
    }

    /**
     * 解析类的字段
     */
    private List<ApiInfo.Parameter> parseClassFields(ClassOrInterfaceDeclaration classDecl) {
        List<ApiInfo.Parameter> fields = new ArrayList<>();

        for (FieldDeclaration fieldDecl : classDecl.getFields()) {
            // 跳过静态字段和常量
            if (fieldDecl.isStatic() || fieldDecl.isFinal()) {
                continue;
            }

            for (VariableDeclarator variable : fieldDecl.getVariables()) {
                ApiInfo.Parameter field = parseField(fieldDecl, variable);
                fields.add(field);
            }
        }

        return fields;
    }

    /**
     * 解析单个字段
     */
    private ApiInfo.Parameter parseField(FieldDeclaration fieldDecl, VariableDeclarator variable) {
        ApiInfo.Parameter field = new ApiInfo.Parameter();

        // 设置字段名称
        String fieldName = variable.getNameAsString();
        field.setParameterName(fieldName);

        // 解析字段描述
        String fieldDesc = parseFieldDescription(fieldDecl);
        field.setParameterDesc(fieldDesc.isEmpty() ? fieldName : fieldDesc);

        // 解析字段类型
        Type fieldType = variable.getType();
        String typeName = fieldType.asString();
        field.setParameterType(typeName);
        field.setSimpleTypeName(getSimpleTypeName(typeName));
        field.setIsPrimitive(isPrimitiveType(typeName));

        // 解析字段注解
        parseFieldAnnotations(fieldDecl, field);

        // 递归解析复杂类型
        if (!Boolean.TRUE.equals(field.getIsPrimitive())) {
            try {
                ResolvedType resolvedFieldType = fieldType.resolve();
                field.setParameterType(resolvedFieldType.describe());
                field.setIsPrimitive(isPrimitiveType(resolvedFieldType.describe()));

                if (!Boolean.TRUE.equals(field.getIsPrimitive())) {
                    field.setFields(resolveTypeFields(resolvedFieldType));
                }
            } catch (Exception e) {
                log.debug("无法解析字段类型: {}.{}", fieldName, typeName);
            }
        }

        return field;
    }

    /**
     * 解析字段描述
     */
    private String parseFieldDescription(FieldDeclaration fieldDecl) {
        Optional<JavadocComment> javadocComment = fieldDecl.getJavadocComment();
        if (javadocComment.isPresent()) {
            Javadoc javadoc = javadocComment.get().parse();
            return javadoc.getDescription().toText().trim();
        }
        return "";
    }

    /**
     * 解析字段注解
     */
    private void parseFieldAnnotations(FieldDeclaration fieldDecl, ApiInfo.Parameter field) {
        for (AnnotationExpr annotation : fieldDecl.getAnnotations()) {
            String annotationName = getSimpleAnnotationName(annotation.getNameAsString());

            // 解析验证注解
            if ("NotNull".equals(annotationName) || "NonNull".equals(annotationName)) {
                field.setNullable(false);
            } else if ("NotEmpty".equals(annotationName) || "NotBlank".equals(annotationName)) {
                field.setNullable(false);
            }
        }
    }

    /**
     * 获取简单类型名称
     */
    private String getSimpleTypeName(String fullTypeName) {
        if (fullTypeName.contains("<")) {
            fullTypeName = fullTypeName.substring(0, fullTypeName.indexOf("<"));
        }

        int lastDot = fullTypeName.lastIndexOf('.');
        return lastDot >= 0 ? fullTypeName.substring(lastDot + 1) : fullTypeName;
    }

    /**
     * 获取简单注解名称
     */
    private String getSimpleAnnotationName(String fullName) {
        int lastDot = fullName.lastIndexOf('.');
        return lastDot >= 0 ? fullName.substring(lastDot + 1) : fullName;
    }

    /**
     * 清理缓存
     */
    public void clearCache() {
        typeCache.clear();
    }
}